#ifndef HOST_H
#define HOST_H
#include "Exchange.hpp"
#include "Queue.hpp"
#include "Message.hpp"
#include "Binding.hpp"
#include <cassert>
#include <memory>
#include <string>
using namespace std;

class VirtualHost
{
public:
    using ptr = shared_ptr<VirtualHost>;
    VirtualHost(const string &hname, const string &basedir, const string &dbfile):
        _host_name(hname),
        _emp(make_shared<ExchangeManager>(dbfile)),
        _qmp(make_shared<QueueManager>(dbfile)),
        _bmp(make_shared<BindingManager>(dbfile)),
        _mmp(make_shared<MessageManager>(basedir))
    {
        //获取到所有的队列信息，通过队列名称恢复历史消息数据
        QueueMapper::QueueMap qm = _qmp->allQueues();
        for (auto &q : qm)
            _mmp->InitQueueMessage(q.first);
    }

    bool DeclareExchange(const string& name,
        MessageQueue::ExchangeType type, 
        bool durable, bool auto_delete,
        const google::protobuf::Map<string, string>& args)
    {
        return _emp->DeclareExchange(name, type, durable, auto_delete, args);
    }

    void DeleteExchange(const string& name)
    {
        _bmp->RemoveExchangeBindings(name);
        return _emp->DeleteExchange(name);
    }

    bool ExistsExchange(const string& name)
    {
        return _emp->exists(name);
    }

    Exchange::ptr SelectExchange(const string& ename)
    {
        return _emp->selectExchange(ename);
    }

    bool DeclareQueue(const string &qname, 
        bool qdurable, 
        bool qexclusive,
        bool qauto_delete,
        const google::protobuf::Map<string, string> &qargs)
    {
        _mmp->InitQueueMessage(qname);
        return _qmp->declareQueue(qname, qdurable, qexclusive, qauto_delete, qargs);
    }

    void DeleteQueue(const string& name)
    {
        // 删除时，要删除队列消息和队列的绑定消息
        _mmp->DestroyQueueMessage(name);
        _bmp->RemoveQueueBindings(name);
        return _qmp->deleteQueue(name);
    }

    bool ExistsQueue(const string& name)
    {
        return _qmp->exists(name);
    }

    QueueMapper::QueueMap Allqueues()
    {
        return _qmp->allQueues();
    }

    bool Bind(const string& ename, const string& qname, const string& key)
    {
        Exchange::ptr ep = _emp->selectExchange(ename);
        if(ep.get() == nullptr)
        {
            lg(Error, "进行队列绑定失败，交换机：%s 不存在", ename.c_str());
            return false;
        }
        Queue::ptr qp = _qmp->selectQueue(qname);
        if(qp.get() == nullptr)
        {
            lg(Error, "进行队列绑定失败，队列：%s 不存在", qname.c_str());
            return false;
        }
        return _bmp->bind(ename, qname, key, ep->durable && qp->durable);
    }

    void UnBind(const string& ename, const string& qname)
    {
        return _bmp->unbind(ename, qname);
    }

    QueueBindingMap ExchangeBindings(const string& ename)
    {
        return _bmp->getExchangeBindings(ename);
    }

    bool ExistsBinding(const string& ename, const string& qname)
    {
        return _bmp->exists(ename, qname);
    }

    bool BasicPublish(const string& qname, MessageQueue::BasicProperties* bp, const string& body)
    {
        Queue::ptr qp = _qmp->selectQueue(qname);
        if(qp.get() == nullptr)
        {
            lg(Error, "发布消息失败，队列：%s 不存在", qname.c_str());
            return false;
        }
        return _mmp->Insert(qname, bp, body, qp->durable);
    }

    mymessageptr::MessagePtr BasicConsume(const string& qname)
    {
        return _mmp->Front(qname);
    }

    void BasicAck(const string& qname, const string& msgid)
    {
        return _mmp->ack(qname, msgid);
    }

    void clear()
    {
        _emp->clear();
        _qmp->clear();
        _bmp->clear();
        _mmp->clear();
    }

private:
    string _host_name;
    ExchangeManager::ptr _emp;
    QueueManager::ptr _qmp;
    BindingManager::ptr _bmp;
    MessageManager::ptr _mmp;
};

#endif